﻿using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;

namespace MyLib
{
	public class ActorExport : Attribute
	{
	}

	public class PlayerActor : Actor
	{
		private uint agentId;
		private Agent agent;
		private Room room;
		public async Task SetRoom(Room r)
		{
			await _messageQueue;
			room = r;
		}

		private static Dictionary<string, MethodInfo> methods = new Dictionary<string, MethodInfo>();
		static PlayerActor()
		{
			var met = typeof(PlayerActor).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
				.Where(m => m.GetCustomAttributes(typeof(ActorExport), false).Length > 0).ToArray();
			Console.WriteLine("PlayerActorInit:"+met.Count());
			/*
			foreach (var m in met)
			{
				var attr = m.GetCustomAttributes(typeof(ActorExport), false);
				Console.WriteLine("Methods: "+m.Name+attr.Length);
			}
			*/
			foreach (var m in met)
			{
				methods.Add(m.Name, m);
			}
		}

		public PlayerActor()
		{
		}
		public PlayerActor(uint playerId)
		{
			agentId = playerId;
			var server = ActorManager.Instance.GetActor<SocketServer>();
			agent = server.GetAgent(agentId);
			agent.actor = this;

		}

		private void InitPlayerId()
		{
			var cmd = GCPlayerCmd.CreateBuilder();
			cmd.Result = string.Format("Init {0}", Id);

			ServerBundle bundle;
			var bytes = ServerBundle.sendImmediateError(cmd, 0, 0, out bundle);
			ServerBundle.ReturnBundle(bundle);

			agent.SendBytes(bytes);
		}

		public override void Init()
		{
			InitPlayerId();
			RunTask(Dispatch);
		}

		protected override async Task ReceiveMsg(ActorMsg msg)
		{

			if (!string.IsNullOrEmpty(msg.msg))
			{
				var cmds = msg.msg.Split(' ');
				if (cmds[0] == "close")
				{
					await RemovePlayer();
				}
			}
			else {
				LogHelper.Log("PlayerActor", "Receive:"+msg.packet.protoBody.ToString());
				var pb = msg.packet.protoBody;
				if (pb is CGPlayerCmd)
				{
					var cmd = msg.packet.protoBody as CGPlayerCmd;
					var cmds = cmd.Cmd.Split(' ');
					var mn = cmds[0];


					MethodInfo methodInfo = null;
					var find = methods.TryGetValue(mn, out methodInfo);

					if (methodInfo != null)
					{
						var ta = (Task)(methodInfo.Invoke(this, new object[] { cmd }));
						await ta;
					}
				}
			}
		}


		[ActorExport]
		private async Task Match(CGPlayerCmd cmd)
		{
			LogHelper.Log("Match", cmd.ToString());
			var lobby = ActorManager.Instance.GetActor<Lobby>();
			await lobby.FindRoom(Id);
		}

		[ActorExport]
		private async Task MakeMove(CGPlayerCmd cmd)
		{
			await room.MakeMove(Id, cmd);
		}

		[ActorExport]
		private async Task Leave()
		{
			await room.Leave(Id);
		}

		public Agent GetAgent()
		{
			return agent;
		}

		private async Task RemovePlayer()
		{
			if (room != null)
			{
				await room.Leave(Id);
			}

			ActorManager.Instance.RemoveActor(Id);
			LogHelper.Log("PlayerActor", "CloseActor " + Id);

		}
	}
}
